package models

import (
	"awesome-devops/applications/devops/dev"
	"awesome-devops/applications/tools"
	"awesome-devops/helper"
	"errors"
	"fmt"
	"gitee.com/jjawesomejj/awesome-util/config"
	"gitee.com/jjawesomejj/awesome-util/helper/commonhelper"
	"gitee.com/jjawesomejj/awesome-util/helper/timeHelper"
	"gorm.io/gorm"
	"strconv"
	"strings"
)

const RUN_STEP_BASIC = 0  //在宿主机上执行
const RUN_STEP_DOCKER = 1 //在容器内执行构建任务

type RunStep struct {
	BaseModel
	StepName     string `json:"step_name"`
	ID           uint   `json:"id"`
	ProcessId    int    `json:"process_id"`
	ProjectId    int    `json:"project_id"`
	StepTemplate string `json:"step_template"`
	TemplateId   int    `json:"template_id"`
	RunType      int    `json:"run_type"`
	RunStep      int    `json:"run_step"`
	DockerImage  string `json:"docker_image"`
	TemplateArgs string `json:"template_args"`
	ExtParams    string `json:"ext_params"`
	UniqueId     string `json:"unique_id"`
	CreateTime   string `json:"create_time"`
	UpdateTime   string `json:"update_time"`
	DeleteTime   int    `json:"delete_time"`
}

func (baseModel *RunStep) BeforeCreate(tx *gorm.DB) (err error) {
	baseModel.CreateTime = timeHelper.Now()
	baseModel.UpdateTime = timeHelper.Now()
	return tx.Error
}

func (baseModel *RunStep) GetRunShell(sysArgs map[string]string, runningArgs map[string]string) (runShell string, err error) {
	args := make(map[string]string)
	argsData, err := commonhelper.JsonDecodeWithErr(baseModel.TemplateArgs)
	if err == nil {
		args = argsData.(map[string]string)
	} else {
		fmt.Println("配置了错误的参数:" + baseModel.TemplateArgs)
	}
	template := baseModel.StepTemplate
	template = baseModel.format(template, sysArgs)
	template = baseModel.format(template, args)
	template = baseModel.format(template, runningArgs)
	template = strings.Replace(template, "\r", "", -1)
	return template, nil
}

func (baseModel *RunStep) GetAfterRunningDriver(serverConfig *ServerConfig, sysArgs map[string]string, runningArgs map[string]string, WorkDir string) (dev.StepStream, error) {
	template, err := baseModel.GetRunShell(sysArgs, runningArgs)
	if err != nil {
		return nil, err
	}
	return &dev.RemoteRunStep{
		Shell:     template,
		WorkDir:   WorkDir,
		UserName:  serverConfig.SshUser,
		Ipaddress: serverConfig.SshIp,
		Port:      serverConfig.SshPort,
	}, nil
}

func (baseModel *RunStep) GetRunningDriver(gitCommand *tools.GitCommand, sysArgs map[string]string, runningArgs map[string]string, WorkDir string) (dev.Step, error) {
	template, err := baseModel.GetRunShell(sysArgs, runningArgs)
	if err != nil {
		return nil, err
	}
	if baseModel.RunType == RUN_STEP_BASIC {
		return &dev.BasicBuildStep{
			Shell:    template,
			WorkPath: WorkDir,
		}, nil
	}
	if baseModel.RunType == RUN_STEP_DOCKER {
		return &dev.DockerStep{
			DockerImage: baseModel.DockerImage,
			RunShell:    template,
			ProjectMntDir: config.GetConfigByKey("projectMntDir", func() interface{} {
				return "/"
			}).(string) + "/" + gitCommand.GitProjectPath,
			ProjectName: gitCommand.ResolveProjectName(),
			ProjectDir:  gitCommand.GitProjectPath,
		}, nil
	}
	return nil, errors.New("未找到对应的driver")
}

func (baseModel *RunStep) GetExtParams(key string, defaultValue string) string {
	params := helper.GetCommandParamsFormStr(baseModel.ExtParams)
	if value, ok := params[key]; ok {
		return value
	}
	return defaultValue
}

func (baseModel *RunStep) GetBuildTimeout() int {
	timeoutInt := GetExtParams(baseModel, "buildTimeout", 30, func(value interface{}) (interface{}, bool) {
		switch value.(type) {
		case string:
			newValue, err := strconv.Atoi(value.(string))
			if err != nil {
				return "", false
			}
			if newValue > 0 {
				return newValue, true
			}
			break
		case float64:
			valueInt := int(value.(float64))
			if valueInt > 0 {
				return valueInt, true
			}
			break
		}
		return "", false
	})
	return timeoutInt.(int)
}

func (baseModel *RunStep) format(shell string, sysArgs map[string]string) (runShell string) {
	for key, value := range sysArgs {
		shell = strings.ReplaceAll(shell, "{{"+key+"}}", value)
	}
	return shell
}

func (baseModel *RunStep) TableName() string {
	return "ops_publish_process_step"
}
